#ifndef TCP_HEADERS
#define TCP_HEADERS
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdint.h>
#endif

#ifndef STRING_H
#define STRING_H
#include <string>
#endif

#ifndef TCPCONN_H
#define TCPCONN_H
#include "TCPConnection.h"
#endif

#define BACKLOG_MAX 1024
#define BUFFER_SIZE 4096
#define RAW_TYPE_SERVER 12
#define SERV_END_SIGNAL 13
class TCPServer {
	sockaddr_in host_to_addr(std::string _host, unsigned short _port);
	unsigned short port;
	int conn_number;
	int maxfdp;
	int rset;
	int maxclient;
	char* namelist;
	struct timeval tv;	
	uint8_t buffer[BUFFER_SIZE];
	unsigned short serv_raw_port;
	int burst_time;
	int round_time;
	RawListener stcp_raw;
	RawListener sudp_raw;
	RawListener sicmp_raw;
	map<int, int> recv_list;
	map<int, double> anr_list;

public:
	struct sockaddr_in myaddr;
	int incoming_sock;
	TCPServer(std::string _ip, unsigned short _port, unsigned short _raw_port) {
		port = _port;
		// Get host information
		myaddr = host_to_addr(_ip, _port);
		// Initialize socket
		incoming_sock = socket(AF_INET, SOCK_STREAM, 0);
		int result = bind(incoming_sock,
				(struct sockaddr*)&myaddr,
				sizeof(struct sockaddr_in));
		if (result < 0)
		{
			std::string err_msg = "";
			if(errno == EACCES) {
				err_msg = "bind: permission denied.";
			}
			else if(EINVAL) {
				err_msg = "Socket is already bound to an address.";
			}
			else if(ENAMETOOLONG) {
				err_msg = "Address is too long.";
			}
			else {
				err_msg = "Could not bind socket to port";
			}
			printf("Error: %s\n", err_msg.c_str());
			incoming_sock = null;
		}
		else {
			result = listen(incoming_sock, BACKLOG_MAX);
			if(result < 0) {
				std::string err_msg = "";
				if(errno == EADDRINUSE) {
					err_msg = "Port is already in use.";
				}
				else {
					err_msg = "Could not listen on port.";
				}
				printf("Error: %s\n", err_msg.c_str());
				incoming_sock = null;
			}
		}
		serv_raw_port = _raw_port;
		printf("ServerRawPort: %d\n", serv_raw_port);
	}

	TCPConnection receive_incoming_connection();
	void stop_server();
	void handle_server_connection(TCPServer server, TCPConnection conn, char* sock_message);
};
